﻿using App.Core.ServiceImpls;
using AppTemplate.Infrastructure.DependencyInjection;
using AppTemplate.UI.Framework;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Serilog;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Windows.Controls;

namespace AppTemplate.UI.Sys
{

    public static class DI
    {
        private static ServiceProvider serviceProvider = null;

        public static void Init(IConfiguration configuration)
        {
            IServiceCollection serviceCollection = new ServiceCollection();

            AutoRegisterDependencies(serviceCollection, configuration);
            ManualServiceRegister.Register(serviceCollection, configuration);

            serviceProvider = serviceCollection.BuildServiceProvider();
        }

        /// <summary>
        /// 自动发现并注册需要注入的项
        /// </summary>
        private static void AutoRegisterDependencies(IServiceCollection serviceCollection, IConfiguration configuration)
        {
            //遍历所有程序集，包括未加载近app domain的,以免漏掉某些延迟加载的模块
            List<Assembly> assams = new List<Assembly>();
            var assamFiles = Directory.GetFiles(AppDomain.CurrentDomain.BaseDirectory, "*.dll");
            assamFiles.Concat(Directory.GetFiles(AppDomain.CurrentDomain.BaseDirectory, "*.exe"));
            foreach(var f in assamFiles)
            {
                try
                {
                    assams.Add(Assembly.LoadFrom(f));
                }
                catch(Exception ex)
                {
                    Log.Information($"启动时加载程序集异常:{ex.Message}", ex);
                }
            }

            var types = assams.SelectMany(i => i.DefinedTypes).Where(t => !t.IsInterface && !t.IsAbstract && (t.IsAssignableTo(typeof(UserControl)) || t.IsAssignableTo(typeof(ViewModel)) || t.CustomAttributes.Any(a => a.AttributeType == typeof(InjectAttribute))));

            foreach (var type in types)
            {
                var attr = type.GetCustomAttribute<InjectAttribute>();
                if (attr != null)
                {
                    if (attr.Ignored)
                        continue;

                    RegisterByAttribute(serviceCollection, type, attr);
                }
                else
                {
                    serviceCollection.AddTransient(type);
                }
            }
        }

        /// <summary>
        /// 登记被InjectAttribute标记的依赖项
        /// </summary>
        private static void RegisterByAttribute(IServiceCollection serviceCollection, TypeInfo type, InjectAttribute attr)
        {
            var interfaces = type.ImplementedInterfaces;
            if (interfaces.Any())
            {
                foreach (var i in interfaces)
                {
                    if (attr.LifeTime == InjectionLifeTime.Transient)
                        serviceCollection.AddTransient(i, type);
                    else if (attr.LifeTime == InjectionLifeTime.Scoped)
                        serviceCollection.AddScoped(i, type);
                    else if (attr.LifeTime == InjectionLifeTime.Singleton)
                        serviceCollection.AddSingleton(i, type);
                }
            }
            else
            {
                if (attr.LifeTime == InjectionLifeTime.Transient)
                    serviceCollection.AddTransient(type);
                else if (attr.LifeTime == InjectionLifeTime.Scoped)
                    serviceCollection.AddScoped(type);
                else if (attr.LifeTime == InjectionLifeTime.Singleton)
                    serviceCollection.AddSingleton(type);
            }
        }
        /// <summary>
        /// 解析服务
        /// </summary>
        /// <typeparam name="T">服务类型</typeparam>
        /// <returns>实例</returns>
        public static T Resolve<T>() where T : notnull
        {
            return serviceProvider.GetRequiredService<T>();
        }
        /// <summary>
        /// 根据类型获取实例
        /// </summary>
        /// <param name="type"></param>
        /// <returns></returns>
        public static object Resolve(Type type)
        {
            return serviceProvider.GetRequiredService(type);
        }

    }
}
